package com.maschinenstuermer.profiler;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Iterator;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;

public class AttachProfiler {
	/**
	 * System property to identify vm running this app.
	 */
	private static final String IT_S_ME = "it's me";

	private final SortedMap<String, VirtualMachineDescriptor> vmDescriptors = 
		new TreeMap<String, VirtualMachineDescriptor>();
	
	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(final String[] args) throws Exception {
		final AttachProfiler attachProfiler = new AttachProfiler();
		attachProfiler.printRunningVms();
		final VirtualMachineDescriptor vmDesc = attachProfiler.chooseVm();
		if (vmDesc != null) {
			attachProfiler.attach(vmDesc);
		}
	}
	
	public void attach(final VirtualMachineDescriptor vmDesc) throws Exception {
		final VirtualMachine vm = VirtualMachine.attach(vmDesc);
		final String agentFile = getAgentFile();
		final String configFile = getResource(AttachProfiler.class, "example.ejb3.config");
		vm.loadAgent(agentFile, configFile);
	}

	public static String getResource(final Class<?> clazz, final String fileName) {
		final ClassLoader classLoader = clazz.getClassLoader();
		final Package pkg = clazz.getPackage();
		final String name = pkg.getName();
		final String packageLocation = name.replaceAll("\\.", "/");
		final String testConfigLocation = packageLocation + "/" + fileName;
		final URL resource = classLoader.getResource(testConfigLocation);
		try {
			return resource.toURI().getPath();
		} catch (URISyntaxException e) {
			throw new IllegalStateException(e);
		}
	}

	private VirtualMachineDescriptor chooseVm() {
		JFrame frame = new JFrame("Attach Profiler");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
		final String selectedVm = (String) JOptionPane.showInputDialog(frame,
		                    "Attach to vm:",
		                    "Attach Profiler",
		                    JOptionPane.INFORMATION_MESSAGE,
		                    null,
		                    vmDescriptors.keySet().toArray(),
		                    null);
		frame.dispose();
		
		final VirtualMachineDescriptor vm = selectedVm == null ? 
				null : vmDescriptors.get(selectedVm);
		return vm;
	}

	public AttachProfiler() throws Exception {
		System.setProperty(IT_S_ME, "");
		initVmDescriptors();
	}
	
	private void initVmDescriptors() throws Exception {
		for (final VirtualMachineDescriptor vmDesc : VirtualMachine.list()) {
			final VirtualMachine vm = VirtualMachine.attach(vmDesc);
			final boolean isAnotherVm = !vm.getSystemProperties().containsKey(IT_S_ME);
			if (isAnotherVm) {
				String displayName = vmDesc.displayName();
				if (displayName.length() > 79) {
					displayName = displayName.substring(0, 79) + "\u2026";
				}
				vmDescriptors.put(displayName, vmDesc);
			}
			vm.detach();
		}
	}

	private String getAgentFile() throws IOException, FileNotFoundException {
		final String profilerArtifactPropertiesFile = getResource(getClass(), "profiler-artifact.properties");
		final Properties artifactProperties = new Properties();
		artifactProperties.load(new FileInputStream(profilerArtifactPropertiesFile));
		final String agentFile = artifactProperties.getProperty("agent.file");
		return agentFile;
	}

	public void printRunningVms() throws Exception {
		final Iterator<String> displayNames = vmDescriptors.keySet().iterator();
		for (int vmIndex = 0; vmIndex < vmDescriptors.size(); vmIndex++) {
			System.out.println(String.format("%d) %s", vmIndex++, displayNames.next()));
		}
	}
}
